unit uSpecialFolder;

interface

type
  TSpecialFolder = record
  private
    class function GetSpecialFolder(CSIDL: Integer) : string; static;
    class function GetProgramFiles : string; static;
    class function GetProgramFilesX86 : string; static;
    class function GetUserDocuments : string; static;
    class function GetAppData : string; static;
    class function GetCommonAppData : string; static;
    class function getTempPath: string; static;
  public
    class property ProgramFiles : string read GetProgramFiles;
    class property ProgramFilesX86 : string read GetProgramFilesX86;
    class property UserDocuments : string read GetUserDocuments;
    class property UserAppData : string read GetAppData;
    class property CommonAppData : string read GetCommonAppData;
    class property TempPath : string read getTempPath;
  end;

implementation

uses
  ShlObj, Windows, ActiveX, SysUtils, IOUtils;

{ TSpecialFolder }

class function TSpecialFolder.GetUserDocuments: string;
begin
  result := GetSpecialFolder(CSIDL_MYDOCUMENTS);
end;

class function TSpecialFolder.GetAppData: string;
begin
  result := GetSpecialFolder(CSIDL_APPDATA);
end;

class function TSpecialFolder.GetCommonAppData: string;
begin
  result := GetSpecialFolder(CSIDL_COMMON_APPDATA);
end;

class function TSpecialFolder.GetProgramFiles: string;
begin
  result := GetSpecialFolder(CSIDL_PROGRAM_FILES);
end;

class function TSpecialFolder.GetProgramFilesX86: string;
begin
  result := GetSpecialFolder(CSIDL_PROGRAM_FILESX86);
end;

class function TSpecialFolder.GetSpecialFolder (CSIDL: Integer) : String;
var
  ItemIDList: PItemIDList;
  sFolderPath : String;
  iSystemFolder : Integer;
  pMalloc : IMalloc;
begin
  pMalloc := nil;
  sFolderPath := '';
  SHGetMalloc (pMalloc);
  if (pMalloc = nil)
    then begin
      Exit;
    end;
  try
    iSystemFolder := CSIDL;
    if (SUCCEEDED (SHGetSpecialFolderLocation (0, iSystemFolder, ItemIDList)))
      then begin
        SetLength (sFolderPath, MAX_PATH);
        if (SHGetPathFromIDList(ItemIDList, PChar(sFolderPath)))
          then begin
            SetLength (sFolderPath, Length(PChar(sFolderPath)));
          end;
      end;
  finally
    Result := sFolderPath;
    pMalloc.Free(ItemIDList);
  end;
end;

class function TSpecialFolder.getTempPath: string;
begin
  result := IncludeTrailingPathDelimiter(TPath.GetTempPath);
end;

end.

